package com.tbynet.jwp.framework.core;

import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.tbynet.jwp.framework.exception.BusinessException;

import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

/**
 * 通用管理器基类 - 服务编排层
 * *
 * 核心职责：
 * 1. 业务逻辑编排：组合多个Service方法完成复杂业务用例
 * 2. 事务管理：确保业务操作的原子性和一致性
 * 3. 缓存管理：统一缓存操作，提高性能
 * 4. 异步处理：处理耗时操作，提高响应速度
 * 5. 性能监控：监控方法执行时间和成功率
 * *
 * 设计原则：
 * - 业务导向：一个方法完成一个完整的业务用例
 * - 事务边界：在管理器层定义事务边界
 * - 无SQL：不包含任何SQL代码，只编排Service方法
 * - 统一响应：提供统一的成功/错误响应格式
 *
 * @author 佰亿互联
 * @version 3.1
 * @since 2025-11-04
 */
public abstract class JwpService {

    /** 日志记录器 */
    protected final Log log = Log.getLog(this.getClass());

    /** 性能监控统计 */
    private final Map<String, AtomicInteger> methodCallCount = new ConcurrentHashMap<>();
    private final Map<String, AtomicInteger> methodErrorCount = new ConcurrentHashMap<>();

    /** 异步任务执行器 */
    private final ExecutorService asyncExecutor = JwpExecutor.getInstance().getExecutorService();

    /** 缓存管理器 */
    protected final JwpCache cache = new JwpCache();

    // ========== 事务管理方法 ==========

    /**
     * 在事务中执行操作
     *
     * @param operation 事务操作，返回boolean表示操作是否成功
     * @return boolean 执行成功返回true，失败返回false
     *
     * @example
     * <pre>{@code
     * boolean success = executeInTransaction(() -> {
     *     boolean result1 = service1.update(data1);
     *     boolean result2 = service2.save(data2);
     *     return result1 && result2;
     * });
     * }</pre>
     */
    protected boolean executeInTransaction(TransactionalOperation operation) {
        return executeWithMonitoring("transaction", () ->
                Db.tx(operation::execute)
        );
    }

    /**
     * 在事务中执行操作（带重试机制）
     *
     * @param operation 事务操作
     * @param maxRetries 最大重试次数，必须 >= 0
     * @param baseDelay 指数退避（毫秒），必须 > 0
     * @return boolean 执行成功返回true，失败返回false
     *
     * @example
     * <pre>{@code
     * boolean success = executeInTransactionWithRetry(() -> {
     *     return service.process(data);
     * }, 3, 1000L);
     * }</pre>
     */
    protected boolean executeInTransactionWithRetry(TransactionalOperation operation,
                                                    int maxRetries, long baseDelay) {
        Validate.isTrue(maxRetries >= 0, "maxRetries必须大于等于0");
        Validate.isTrue(baseDelay > 0, "baseDelay必须大于0");

        int attempt = 0;
        while (attempt <= maxRetries) {
            if (executeInTransaction(operation)) {
                return true;
            }

            attempt++;
            if (attempt <= maxRetries) {
                // 指数退避 + 随机抖动（0-500ms）
                long delay = (long) (baseDelay * Math.pow(2, attempt) + new Random().nextInt(500));
                log.warn("事务执行失败，第%s次重试（延迟%sms）...", attempt, delay);
                sleepWithInterrupt(delay);
            }
        }

        log.error("事务执行失败，已达到最大重试次数: %s", maxRetries);
        return false;
    }

    // ========== 异步任务管理 ==========

    /**
     * 异步执行任务
     *
     * @param task 异步任务，无返回值
     * @param taskName 任务名称（用于日志记录）
     * @return CompletableFuture<Void> 异步执行结果
     *
     * <pre>{@code
     * executeAsync(() -> {
     *     emailService.sendWelcomeEmail(user);
     * }, "发送欢迎邮件");
     * }</pre>
     */
    protected CompletableFuture<Void> executeAsync(Runnable task, String taskName) {
        return CompletableFuture.runAsync(() ->
                executeWithMonitoring(taskName, () -> {
                    task.run();
                    return null;
                }), asyncExecutor);
    }

    /**
     * 带返回值的异步执行
     *
     * @param task 异步任务，返回指定类型结果
     * @param taskName 任务名称
     * @param <T> 返回值类型
     * @return CompletableFuture<T> 异步执行结果
     *
     * <pre>{@code
     * CompletableFuture<List<User>> future = executeAsync(() ->
     *     userService.findActiveUsers(), "查询活跃用户");
     * }</pre>
     */
    protected <T> CompletableFuture<T> executeAsync(Supplier<T> task, String taskName) {
        return CompletableFuture.supplyAsync(() ->
                executeWithMonitoring(taskName, task::get), asyncExecutor);
    }

    /**
     * 带超时的异步执行
     *
     * @param task 异步任务
     * @param taskName 任务名称
     * @param timeout 超时时间
     * @param timeUnit 时间单位
     * @param <T> 返回值类型
     * @return T 执行结果，超时或异常时返回null
     *
     * <pre>{@code
     * List<User> users = executeAsyncWithTimeout(
     *     () -> userService.findLargeDataset(),
     *     "查询大数据集",
     *     30, TimeUnit.SECONDS
     * );
     * }</pre>
     */
    protected <T> T executeAsyncWithTimeout(Supplier<T> task, String taskName,
                                            long timeout, TimeUnit timeUnit) {
        try {
            CompletableFuture<T> future = executeAsync(task, taskName);
            return future.get(timeout, timeUnit);
        } catch (TimeoutException e) {
            log.warn("异步任务执行超时: %s, 超时时间: %s%s", taskName, timeout, timeUnit);
            return null;
        } catch (Exception e) {
            log.error("异步任务执行异常: %s", taskName, e);
            return null;
        }
    }

    // ========== 响应构建方法 ==========

    /**
     * 构建成功响应
     *
     * @param message 成功消息
     * @param data 返回数据（可选）
     * @return Ret 成功响应对象
     *
     * <pre>{@code
     * return buildSuccess("用户创建成功", user);
     * }</pre>
     */
    protected Ret buildSuccess(String message, Object data) {
        Ret ret = Ret.ok("msg", message);
        if (data != null) {
            ret.set("data", data);
        }
        return ret;
    }

    /**
     * 构建分页成功响应
     *
     * @param message 成功消息
     * @param data 数据列表
     * @param page 分页对象
     * @return Ret 分页成功响应对象
     *
     * <pre>{@code
     * return buildPageSuccess("查询成功", userList, page);
     * }</pre>
     */
    protected Ret buildPageSuccess(String message, Object data, Page<?> page) {
        return Ret.ok("msg", message)
                .set("data", data)
                .set("pageNumber", page.getPageNumber())
                .set("pageSize", page.getPageSize())
                .set("totalPage", page.getTotalPage())
                .set("totalRow", page.getTotalRow());
    }

    /**
     * 构建参数错误响应
     *
     * @param field 参数字段名
     * @param message 错误消息
     * @return Ret 参数错误响应对象
     *
     * <pre>{@code
     * return buildParamError("email", "邮箱格式不正确");
     * }</pre>
     */
    protected Ret buildParamError(String field, String message) {
        return Ret.fail("code", JwpConstants.ERROR_CODE_PARAM)
                .set("field", field)
                .set("msg", message);
    }

    /**
     * 构建业务错误响应
     *
     * @param code 业务错误码
     * @param message 错误消息
     * @return Ret 业务错误响应对象
     *
     * <pre>{@code
     * return buildBusinessError("USER_EXISTS", "用户已存在");
     * }</pre>
     */
    protected Ret buildBusinessError(String code, String message) {
        return Ret.fail("code", code).set("msg", message);
    }

    /**
     * 构建系统错误响应
     *
     * @param message 系统错误消息
     * @return Ret 系统错误响应对象
     *
     * <pre>{@code
     * return buildSystemError("系统繁忙，请稍后重试");
     * }</pre>
     */
    protected Ret buildSystemError(String message) {
        return Ret.fail("code", JwpConstants.ERROR_CODE_SYSTEM).set("msg", message);
    }

    // ========== 性能监控方法 ==========

    /**
     * 记录方法性能
     *
     * @param methodName 方法名
     * @param startTime 开始时间
     * @param status 执行状态
     */
    protected void logMethodPerformance(String methodName, long startTime, String status) {
        long cost = System.currentTimeMillis() - startTime;
        if (cost > JwpConstants.SLOW_METHOD_THRESHOLD) {
            log.warn("方法执行时间过长: %sms, 方法: %s, 状态: %s", cost, methodName, status);
        } else {
            log.debug("方法执行完成: %sms, 方法: %s, 状态: %s", cost, methodName, status);
        }
    }

    /**
     * 记录方法调用
     *
     * @param methodName 方法名
     */
    protected void recordMethodCall(String methodName) {
        methodCallCount.computeIfAbsent(methodName, k -> new AtomicInteger(0)).incrementAndGet();
    }

    /**
     * 记录方法错误
     *
     * @param methodName 方法名
     */
    protected void recordMethodError(String methodName) {
        methodErrorCount.computeIfAbsent(methodName, k -> new AtomicInteger(0)).incrementAndGet();
    }

    /**
     * 获取方法调用统计
     *
     * @return Map<String, Integer> 方法调用次数统计
     */
    public Map<String, Integer> getMethodCallStatistics() {
        Map<String, Integer> statistics = new HashMap<>();
        methodCallCount.forEach((method, count) -> statistics.put(method, count.get()));
        return statistics;
    }

    /**
     * 获取方法错误统计
     *
     * @return Map<String, Integer> 方法错误次数统计
     */
    public Map<String, Integer> getMethodErrorStatistics() {
        Map<String, Integer> statistics = new HashMap<>();
        methodErrorCount.forEach((method, count) -> statistics.put(method, count.get()));
        return statistics;
    }

    /**
     * 获取方法成功率统计
     *
     * @return Map<String, Double> 方法成功率统计（百分比）
     */
    public Map<String, Double> getMethodSuccessRateStatistics() {
        Map<String, Double> statistics = new HashMap<>();
        methodCallCount.forEach((method, callCount) -> {
            AtomicInteger errorCount = methodErrorCount.get(method);
            int errors = errorCount != null ? errorCount.get() : 0;
            int calls = callCount.get();

            if (calls > 0) {
                double successRate = (calls - errors) * 100.0 / calls;
                statistics.put(method, Math.round(successRate * 100.0) / 100.0);
            } else {
                statistics.put(method, 100.0);
            }
        });
        return statistics;
    }

    // ========== 内部工具方法 ==========

    /**
     * 带监控的执行模板方法
     */
    protected <T> T executeWithMonitoring(String operationName, Supplier<T> operation) {
        String methodName = getCallerMethodName();
        recordMethodCall(methodName);
        long startTime = System.currentTimeMillis();

        try {
            T result = operation.get();
            String status = result instanceof Boolean ?
                    ((Boolean) result ? "SUCCESS" : "FAILED") : "SUCCESS";
            logMethodPerformance(methodName, startTime, status);
            return result;
        } catch (RuntimeException e) {
            // 运行时异常直接抛出（包含RepositoryException）
            recordMethodError(methodName);
            log.error("%s执行异常: %s", operationName, methodName, e);
            throw e;
        } catch (Exception e) {
            // 受检异常包装为RuntimeException
            recordMethodError(methodName);
            log.error("%s执行异常: %s", operationName, methodName, e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 线程安全睡眠（处理中断异常）
     */
    private void sleepWithInterrupt(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("线程被中断", e);
        }
    }

    /**
     * 获取调用方法名
     */
    private String getCallerMethodName() {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        return stackTrace.length > 4 ? stackTrace[4].getMethodName() : "unknown";
    }

    // ========== 内部接口和类 ==========

    /**
     * 事务操作接口
     */
    @FunctionalInterface
    protected interface TransactionalOperation {
        /**
         * 执行事务操作
         * @return boolean 操作是否成功
         * @throws SQLException 数据库异常
         */
        boolean execute() throws SQLException;
    }

    /**
     * 批量操作回调接口
     */
    @FunctionalInterface
    protected interface BatchOperationCallback<T> {
        /**
         * 处理批量操作中的单个项
         * @param item 当前处理项
         * @param index 当前索引
         * @return boolean 处理是否成功
         */
        boolean process(T item, int index);
    }

    /**
     * 参数验证工具类
     */
    private static class Validate {
        /**
         * 验证条件是否为true
         * @param condition 条件
         * @param message 错误消息
         * @throws BusinessException 当条件为false时抛出
         */
        static void isTrue(boolean condition, String message) {
            if (!condition) {
                throw new BusinessException(message);
            }
        }

        /**
         * 验证对象不为null
         */
        public static void notNull(Object obj, String message) {
            if (obj == null) {
                throw new BusinessException(message);
            }
        }

        /**
         * 验证字符串不为空
         */
        public static void notBlank(String str, String message) {
            if (StrKit.isBlank(str)) {
                throw new BusinessException(message);
            }
        }
    }

}